feat: OptiX AI Denoiser — real-time noise reduction#8
Merged
Conversation
Owner
Author
|
LGTM :D |
There was a problem hiding this comment.
Pull request overview
Integrates an NVIDIA OptiX-based denoising pass into the CUDA renderer path to reduce real-time noise, with build-time SDK detection and an ImGui toggle to enable/disable denoising.
Changes:
- Adds OptiX SDK detection to xmake and gates denoiser compilation behind
WL_OPTIX. - Introduces an
OptiXDenoiserRAII wrapper and wires it into the GPU render loop. - Adds a GPU-side HDR denoise buffer plus a conversion kernel to write denoised results back to the RGBA8 output.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
xmake.lua |
Detects OptiX SDK and enables WL_OPTIX, adds include/link settings for OptiX integration. |
RayTracing/src/WalnutApp.cpp |
Adds ImGui “Denoise” checkbox (guarded by WL_OPTIX). |
RayTracing/src/Renderer.h |
Adds denoiser setting/member (and OptiX header include). |
RayTracing/src/Renderer.cpp |
Runs OptiX denoise + reconvert pass after CUDA rendering. |
RayTracing/src/OptiXDenoiser.h |
Declares OptiX denoiser RAII wrapper (and stub interface when disabled). |
RayTracing/src/OptiXDenoiser.cpp |
Implements OptiX context/denoiser lifecycle and per-frame invoke. |
RayTracing/src/CUDARenderer.h |
Exposes denoise buffer + stream accessors and denoised-to-RGBA conversion API. |
RayTracing/src/CUDARenderer.cuh |
Writes averaged HDR output to a denoise buffer and adds ConvertToRGBAKernel. |
RayTracing/src/CUDARenderer.cu |
Allocates denoise buffer and implements new denoise/stream helper APIs. |
Comment on lines
+19
to
+21
| #ifdef WL_OPTIX | ||
| #include "OptiXDenoiser.h" | ||
| #endif |
Comment on lines
+552
to
+555
| cudaStream_t stream = (cudaStream_t)CUDARenderer_GetComputeStream(m_CUDAState); | ||
| if (!m_Denoiser.IsValid()) | ||
| m_Denoiser.Initialize(width, height, stream); | ||
|
|
Comment on lines
+314
to
+325
| void CUDARenderer_ConvertDenoisedToRGBA(CUDARenderState* state, cudaStream_t stream) | ||
| { | ||
| if (!state || !state->initialized || state->pixelCount == 0) return; | ||
|
|
||
| int threads = 256; | ||
| int blocks = (state->pixelCount + threads - 1) / threads; | ||
| ConvertToRGBAKernel<<<blocks, threads, 0, stream>>>( | ||
| (const float4*)state->d_DenoiseBuffer, | ||
| state->d_OutputImage, | ||
| state->pixelCount | ||
| ); | ||
| } |
Comment on lines
+36
to
+49
| // Retrieve current CUDA context (must already exist) | ||
| CUcontext cuCtx = nullptr; | ||
| CUresult cuRes = cuCtxGetCurrent(&cuCtx); | ||
| if (cuRes != CUDA_SUCCESS || cuCtx == nullptr) | ||
| { | ||
| CUdevice cuDevice; | ||
| cuCtxGetDevice(&cuDevice); | ||
| cuRes = cuDevicePrimaryCtxRetain(&cuCtx, cuDevice); | ||
| if (cuRes != CUDA_SUCCESS) | ||
| { | ||
| std::fprintf(stderr, "[OptiX] Failed to get CUDA context\n"); | ||
| return; | ||
| } | ||
| } |
Comment on lines
+87
to
+106
| OPTIX_CHECK(optixDenoiserCreate( | ||
| m_optixContext, OPTIX_DENOISER_MODEL_KIND_HDR, | ||
| &opts, &m_denoiser)); | ||
|
|
||
| if (!m_denoiser) return false; | ||
|
|
||
| OPTIX_CHECK(optixDenoiserComputeMemoryResources( | ||
| m_denoiser, width, height, &m_sizes)); | ||
|
|
||
| cudaMalloc(&m_dStateBuffer, m_sizes.stateSizeInBytes); | ||
| cudaMalloc(&m_dScratchBuffer, m_sizes.withoutOverlapScratchSizeInBytes); | ||
| cudaMalloc(&m_dHdrIntensity, sizeof(float)); | ||
|
|
||
| OPTIX_CHECK(optixDenoiserSetup( | ||
| m_denoiser, (CUstream)stream, | ||
| width, height, | ||
| (CUdeviceptr)m_dStateBuffer, m_sizes.stateSizeInBytes, | ||
| (CUdeviceptr)m_dScratchBuffer, m_sizes.withoutOverlapScratchSizeInBytes)); | ||
|
|
||
| m_valid = true; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Integrates NVIDIA OptiX AI Denoiser for real-time noise reduction in the GPU path tracer. RGB-only denoising (HDR model), activated via ImGui "Denoise" checkbox.
How It Works
d_DenoiseBufferConvertToRGBAKernelconverts denoised float4 → RGBA8Build
Requires OptiX SDK 9.x (
OptiX_ROOTenv var or auto-detection fromC:\ProgramData\NVIDIA Corporation\OptiX SDK *). Without SDK:#ifdef WL_OPTIXguard, stub class, no-op — project builds identically.Changes (3 commits)
4ebc220729d026cb05cd2Files
OptiXDenoiser.hOptiXDenoiser.cppCUDARenderer.cuhCUDARenderer.cuCUDARenderer.hRenderer.hRenderer.cppWalnutApp.cppxmake.luaVerification